home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 2410 / 2410.xpi / chrome / content / foxmarks-bookmark.js next >
Text File  |  2010-01-28  |  11KB  |  310 lines

  1. /*
  2.  Copyright 2007-2008 Foxmarks Inc.
  3.  
  4.  foxmarks-bookmark.js: component that implements the logical interface to
  5.  related to syncing datatypes.
  6.  
  7. For FF2, the heavy lifting is in rdf.js
  8. For FF3, the heavy lifting is in places.js
  9.  */
  10.  
  11.  
  12. function applyCommonBookmarkFunctions(me){
  13.  
  14.     me.DiscontinuityPrompt= function() {
  15.         var sb = Xmarks.Bundle().GetStringFromName;
  16.  
  17.         // get a reference to the prompt service component.
  18.         var ps = Cc["@mozilla.org/embedcomp/prompt-service;1"].
  19.           getService(Ci.nsIPromptService);
  20.  
  21.         var flags = ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_0 +
  22.               ps.BUTTON_TITLE_IS_STRING * ps.BUTTON_POS_1 +
  23.               ps.BUTTON_TITLE_CANCEL    * ps.BUTTON_POS_2;
  24.  
  25.         var rv = ps.confirmEx(null, sb("disc.title"), sb("disc.body"), flags,
  26.             sb("disc.merge"), sb("disc.download"), null, null, {});
  27.  
  28.         return rv;
  29.     };
  30.  
  31.     me.handleNidConflict = function(lnode, snode, conflicts){
  32.         var nodes = { 
  33.             local: lnode,
  34.             server: snode
  35.         };
  36.         var ntype = lnode.ntype;
  37.         var chromeUrl;
  38.  
  39.         if (ntype == "folder") {
  40.             chromeUrl = 
  41.                 "chrome://foxmarks/content/foxmarks-folderconflict.xul";
  42.         // Special case: name-change only for microsummary
  43.         } else if (ntype == "microsummary" && 
  44.                 conflicts.length == 1 && conflicts[0] == "name") {
  45.             return "local";
  46.         } else {
  47.             chromeUrl = 
  48.                 "chrome://foxmarks/content/foxmarks-bookmarkconflict.xul";
  49.         }
  50.         return OpenConflictDialog(chromeUrl, nodes);
  51.     };
  52.     me.ClobberDialog = function(currNum, lastNum) {
  53.  
  54.         // put up Clobber Dialog and return true if user okays
  55.         // sync, otherwise false.
  56.  
  57.         var retval = { okay: false };
  58.  
  59.         var topwin = Cc['@mozilla.org/appshell/window-mediator;1'].
  60.             getService(Ci.nsIWindowMediator).
  61.             getMostRecentWindow(null);
  62.         
  63.         if (!topwin) {
  64.             Xmarks.LogWrite("ClobberDialog: Couldn't find a topwin!");
  65.             return false;
  66.         }
  67.  
  68.  
  69.         var win = topwin.openDialog(
  70.             "chrome://foxmarks/content/foxmarks-clobber.xul", "_blank",
  71.             "chrome,dialog,modal,centerscreen", retval, currNum, lastNum);
  72.  
  73.         Xmarks.LogWrite("ClobberDialog: retval.okay is " + retval.okay);
  74.         
  75.         return retval.okay;
  76.     };
  77.  
  78.     me.getBaselineName = function(){
  79.         return "xmarks-baseline-" + Xmarks.gSettings.hash + "json";
  80.     };
  81.     me.syncType = "bookmarks";
  82.  
  83.     me.merge = function(dest, source) {
  84.         // Merge the given nodeset into us.
  85.         // Walk through our node hiearchy and, in parallel,
  86.         // source's hierarchy. Discard from further consideration any item
  87.         // inside us that loosely matches* anything in the source. For any
  88.         // item that exists in the source but not us, recusrively copy that
  89.         // item into ourselves (being careful to generate new nid's for each
  90.         // copied item).
  91.         //
  92.         // *Loosely matches, in this context, means that the node's ntype,
  93.         // name, and url (if present) match for any two items in the same
  94.         // place in the hiearchy.
  95.  
  96.         var self = this;
  97.         var folders = [[NODE_ROOT, NODE_ROOT]];
  98.         var toolbars = [
  99.             ValidNid(dest, dest.Node(NODE_ROOT, false, true).tnid),
  100.             ValidNid(source, source.Node(NODE_ROOT, false, true).tnid)];
  101.         var unfiledRoots = [
  102.             ValidNid(dest, dest.Node(NODE_ROOT, false, true).unid),
  103.             ValidNid(source, source.Node(NODE_ROOT, false, true).unid)];
  104.         var mergeToolbars = false;
  105.         var mergeUnfiledRoots = false;
  106.         var replicatedTnid = null;
  107.         var replicatedUnid = null;
  108.  
  109.        // var ds = new NativeDatasource();
  110.  
  111.         if (toolbars[0] && toolbars[1]) {
  112.             folders.push(toolbars);
  113.             mergeToolbars = true;
  114.         }
  115.  
  116.         if (unfiledRoots[0] && unfiledRoots[1]) {
  117.             folders.push(unfiledRoots);
  118.             mergeUnfiledRoots = true;
  119.         }
  120.  
  121.         while (folders.length) {
  122.             var f = folders.pop();
  123.             var us = dest.Node(f[0]);
  124.             var them = source.Node(f[1]);
  125.             Xmarks.LogWrite(">> Merge processing folder " + us.name + " (" + 
  126.                     us.nid + ")");
  127.             // makin' copies!
  128.             var ourchildren = us.children ? us.children.slice() : [];
  129.             var theirchildren = them.children ? them.children.slice() : [];
  130.  
  131.             for (var i = 0; i < theirchildren.length; ++i) {
  132.                 var theiritem = theirchildren[i];
  133.                 if (mergeToolbars && theiritem == toolbars[1])
  134.                     continue;   // skip it, we've already processed it
  135.                 if (mergeUnfiledRoots && theiritem == unfiledRoots[1])
  136.                     continue;   // Ditto.
  137.                 var matched = FindMatch(theiritem);
  138.                 if (matched >= 0) {
  139.                     if (dest.Node(ourchildren[matched]).ntype == "folder") {
  140.                         folders.push([ourchildren[matched], theirchildren[i]]);
  141.                     }
  142.                     ourchildren.splice(matched, 1);
  143.                 } else {
  144.                     ReplicateNode(source, theirchildren[i], us.nid);
  145.                 }
  146.             }
  147.         }
  148.  
  149.         if (!toolbars[0] && replicatedTnid) {
  150.             dest.Node(NODE_ROOT, true).tnid = replicatedTnid;
  151.         }
  152.  
  153.         if (!unfiledRoots[0] && replicatedUnid) {
  154.             dest.Node(NODE_ROOT, true).unid = replicatedUnid;
  155.         }
  156.  
  157.         function FindMatch(nid) {
  158.             // nid is an item in source.
  159.             // Try to find the best match in ourchildren.
  160.             // Return the index into ourchildren of the best
  161.             // match or -1 if no match found.
  162.             if (nid == toolbars[1] || nid == unfiledRoots[1])
  163.                 return -1;  // These special roots are never matched here.
  164.             var them = source.Node(nid);
  165.             var themurl = self.NormalizeUrl(them.ntype == "feed" ? 
  166.                     them.feedurl : them.url);
  167.             var themname = NormalizedName(them);
  168.             var matches = []
  169.             for (var i = 0; i < ourchildren.length; ++i) {
  170.                 var child = ourchildren[i];
  171.                 if (child == toolbars[0] || child == unfiledRoots[0])
  172.                     continue;
  173.                 var us = dest.Node(child);
  174.                 var usurl =self.NormalizeUrl(us.ntype == "feed" ? 
  175.                         us.feedurl : us.url);
  176.                 var usname = NormalizedName(us);
  177.  
  178.                 // Don't match if ntypes or urls are different.
  179.                 if (us.ntype != them.ntype || usurl != themurl) {
  180.                     continue;
  181.                 }
  182.  
  183.                 // Only match folders if their name matches.
  184.                 if (us.ntype == 'folder' && usname != themname) {
  185.                     continue;
  186.                 }
  187.  
  188.                 var score = 0;
  189.                 if (usname == themname) score += 2;
  190.                 if (nid == child) ++score;
  191.                 matches.push([i, score]);
  192.             }
  193.             if (!matches.length) {
  194.                 return -1;
  195.             } else if (matches.length > 1) {
  196.                 matches.sort(function(x, y) { return y[1] - x[1] });
  197.             }
  198.             return matches[0][0];
  199.         }
  200.  
  201.         function NormalizedName(node) {
  202.             if (node.ntype == "separator") {
  203.                 return "";
  204.             } else if (node.ntype == "microsummary") {
  205.                 return node.generateduri || rtrim(node.name);
  206.             } else {
  207.                 return rtrim(node.name);
  208.             }
  209.         }
  210.         
  211.         function ReplicateNode(source, nid, pnid) {
  212.             // Copy the given node (including children if it's a folder)
  213.             // into us, generating new nids along the way.
  214.  
  215.             Xmarks.LogWrite("Entered ReplicateNode(" + nid + ")");
  216.  
  217.             function ReplicateNodeInternal(nid, pnid) {
  218.                 if (mergeToolbars && nid == toolbars[1])
  219.                     return;
  220.                 var attrs = source.Node(nid).GetSafeAttrs();
  221.                 attrs.pnid = pnid;
  222.                 var newNid =self.GenerateNid();
  223.                 dest.Do_insert(newNid, attrs);
  224.                 if (nid == toolbars[1]) {
  225.                     replicatedTnid = newNid;
  226.                 } else if (nid == unfiledRoots[1]) {
  227.                     replicatedUnid = newNid;
  228.                 }
  229.  
  230.                 if (attrs.ntype == 'folder') {
  231.                     var children = source.Node(nid).children;
  232.                     if (children) {
  233.                         for (var i = 0; i < children.length; ++i) {
  234.                             ReplicateNodeInternal(children[i], newNid);
  235.                         }
  236.                     }
  237.                 }
  238.             }
  239.  
  240.             // Fun with closures: note that we create ds just once
  241.             // and keep it in a closure as we recursively process
  242.             // nid and its children. Creating a native datasource
  243.             // *could* be expensive, depending on platform, so this
  244.             // is likely justified.
  245.             ReplicateNodeInternal(nid, pnid);
  246.         }
  247.  
  248.         function rtrim(s) {
  249.             return s ? s.replace(/\s+$/, "") : s;
  250.         }
  251.  
  252.         function ValidNid(ns, nid) {
  253.             return ns.Node(nid, false, true) ? nid : null;
  254.         }
  255.     };
  256.  
  257.  
  258.     me.orderIsImportant = true;
  259.     me.IGNORABLE ={ created: true, visited: true, modified: true, private: true };
  260.     me.NONULLFIELDS = { name: true, description: true, shortcuturl: true };
  261.     
  262.     me.compareNodes = function(snode, onode, attrs){
  263.         var important = [];
  264.  
  265.         // Iterate over other's attrs, add mistmach/missings.
  266.         for (var attr in onode) {
  267.             if (attr == "children" || attr == "pnid" ||
  268.                     !onode.hasOwnProperty(attr))
  269.                 continue;
  270.             if (!equals(snode[attr], onode[attr])) {
  271.                 attrs[attr] = onode[attr];
  272.                
  273.                 if(this.NONULLFIELDS[attr] && !attrs[attr]){
  274.                     attrs[attr] = "";
  275.                     Xmarks.LogWrite("Updating Null field: " + attr);
  276.                 }
  277.  
  278.                 if (!this.IGNORABLE[attr]) {
  279.                     important.push(attr);
  280.                 }
  281.             }
  282.         }
  283.  
  284.         // Iterate over self's attrs, add deletions.
  285.         for (var attr in snode) {
  286.             if (attr == "children" || !snode.hasOwnProperty(attr))
  287.                 continue;
  288.             if (!(attr in onode)) {
  289.                 attrs[attr] = null;
  290.                 if(this.NONULLFIELDS[attr]){
  291.                     attrs[attr] = "";
  292.                     Xmarks.LogWrite("Updating Null field: " + attr);
  293.                 }
  294.                 if (!this.IGNORABLE[attr]) {
  295.                     important.push(attr);
  296.                 }
  297.             }
  298.         }
  299.         
  300.         // Special case: don't generate update on microsummary name
  301.         // change.
  302.         if (snode.ntype == "microsummary" && important.length == 1 &&
  303.                 important[0] == 'name') {
  304.             return false;
  305.         }
  306.  
  307.         return important.length > 0;
  308.     };
  309. }
  310.